package com.gitee.wsl.statemachine

import com.gitee.wsl.flow.state.RootStateSource
import com.gitee.wsl.prop.Prop
import com.gitee.wsl.statemachine.state.StateObserver
import com.gitee.wsl.statemachine.transition.StateMachineActionFlow
import com.gitee.wsl.statemachine.trigger.SampleActionTrigger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class StateMachineImp<A,  State> (
    private val initialState: State,
    private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob()),
    private val reducer: Reducer<A,State>
): StateMachine<A, State> {

    private val context by lazy {
        StateMachineContext<A, State>(scope, _state)
    }

    private val _state : RootStateSource<State> by lazy {
        RootStateSource(initialState)
    }

    override val state by lazy {
        _state.asStateFlow()
    }

    override fun observeState(onStateChanged: StateMonitor<A,State>) {
        scope.launch {
            state.collect{
                onStateChanged(this@StateMachineImp,it)
            }
        }
    }

    infix fun observeState(observer: StateObserver<State>) = observer.observe(_state)

    private fun emit(action: A) {
        scope.launch {
            if(context.tryActionAuto(action))
                context.actionAuto(action)
            else
                context.reducer(action, state.value)
        }
    }

    override fun action(action: A) {
        emit(action)
    }

    override fun tryAction(action: A): Boolean {
       return context.tryActionAuto(action)
    }

    fun addActionHandlerMap(actionHandlerMap : Map<State, SampleActionTrigger<State>>){
        context.actionTriggerMap.putAll(actionHandlerMap)
    }

    fun addStateFlowList(stateFlowList:List<StateMachineActionFlow<A, State>>){
        context.stateFlowList.addAll(stateFlowList)
    }

    /**
     * Prop fun
     */

    override fun <T> get(prop: Prop<T>): T? {
        return context.props[prop]
    }

    override fun <T> get(prop: Prop<T>, defValue: T): T {
        return context.props[prop, defValue]
    }

    override fun <T> set(prop: Prop<T>, value: T?) {
        context.props[prop] = value
    }

    override fun <T> clear(prop: Prop<T>) {
        context.props.clear(prop)
    }

    override fun clearAll() {
        context.props.clearAll()
    }

    override fun getTargetStateList(): List<State> {
        /*val stateList= mutableListOf<State>()
        context.stateFlowList.find { it.fromState == state }?.let {
            stateList.add(it.toState)
        }
        return stateList*/
        return context.stateFlowList.filter{ it.fromState == state }.map{ it.toState }
    }

    override fun getNextActionList(): List<A> {
        /*val stateList= mutableListOf<A>()
        context.stateFlowList.find { it.fromState == state }?.let {
            stateList.add(it.action)
        }
        return stateList*/
        return context.stateFlowList.filter{ it.fromState == state }.map{ it.action }
    }
}